﻿Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.ComponentModel
Public Class LineNumber
#Region "属性事件定义"
    ''' <summary>
    ''' 用行号表示区域来选择整行文本
    ''' </summary>
    ''' <param name="StartLineNumber">选中开始行号</param>
    ''' <param name="EndLineNumber">选中结束行号</param>
    ''' <param name="FirstLine">第一个可见行行号</param>
    ''' <remarks></remarks>
    Event SelectTextByLineNumber(ByVal StartLineNumber As Integer, ByVal EndLineNumber As Integer, ByVal FirstLine As Integer)
    ''' <summary>
    ''' 行号单击
    ''' </summary>
    ''' <param name="DisplayLineNo"></param>
    ''' <remarks></remarks>
    Event LineClicked(ByVal DisplayLineNo As Integer)
    ''' <summary>
    ''' 行号双击
    ''' </summary>
    ''' <param name="DisplayLineNo"></param>
    ''' <remarks></remarks>
    Event LineDoubleClicked(ByVal DisplayLineNo As Integer)
#End Region
#Region "内部方法"
    ''' <summary>
    ''' 构造器
    ''' </summary>
    ''' <remarks></remarks>
    Sub New()
        ' 此调用是 Windows 窗体设计器所必需的。
        InitializeComponent()
        ' 在 InitializeComponent() 调用之后添加任何初始化。
        SetStyle(ControlStyles.Selectable, False)
        Me.DoubleBuffered = True
        ExFont = Me.Font
    End Sub
    Private Sub LineNumber_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SizeChanged
        Me.Refresh()
    End Sub
    ''' <summary>
    ''' 重绘
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub LineNumber_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        If Me.Size.Height < 20 Then Exit Sub
        Dim bmp As Bitmap = New Bitmap(Me.Size.Width, Me.Size.Height)
        Dim g As Graphics = Graphics.FromImage(bmp)
        Dim VisibleLines As Byte = Math.Floor((Me.Size.Height) / ExFont.Height)
        Dim DisplayLine As Line
        '擦除画面
        g.Clear(Color.Snow)
        '右边用源代码背景色绘制
        g.FillRectangle(New SolidBrush(ExBackColor), 50, 0, Me.Width - 50, Me.Height)
        For DisplayLineNoForDraw As Integer = FirstVisiableLineNumber To Math.Min(CInt(FirstVisiableLineNumber + VisibleLines - 1), CInt(ExDocument.MaxDisplayLineNumber))
            DisplayLine = ExDocument.GetMemoryLineByDisplayLineNumber(DisplayLineNoForDraw)
            '如果该行拥有关键字
            If ExDocument.GetMemoryLineByDisplayLineNumber(DisplayLineNoForDraw).HasHeightLightWord Then
                g.FillRectangle(Brushes.Gold, 0, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height, 50, ExFont.Height)
            End If
            '列模式
            If ExColumnMode Then
                If DisplayLine.Dis_RealLineNumber >= ColumnStartLine And DisplayLine.Dis_RealLineNumber <= ColumnEndLine Then
                    g.FillRectangle(Brushes.Yellow, 0, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height, 50, ExFont.Height)
                End If
            End If
            '绘制书签
            If DisplayLine.Dis_IsFirstLine And ExDocument.lstBookMark.Contains(DisplayLine.Dis_RealLineNumber) Then
                g.FillRectangle(Brushes.Pink, 0, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height, 50, ExFont.Height)
            End If
            If ExWordWrapMode Then
                If DisplayLine.Dis_IsFirstLine Then
                    g.DrawString(Format(DisplayLine.Dis_RealLineNumber, "0000#"), ExFont, New SolidBrush(Color.Black), 0, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height, StringFormat.GenericTypographic)
                End If
            Else
                g.DrawString(Format(DisplayLine.Dis_RealLineNumber, "0000#"), ExFont, New SolidBrush(Color.Black), 0, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height, StringFormat.GenericTypographic)
            End If
            Dim orgCodeFold As Line.CodeFoldType = DisplayLine.Dis_CodeFold
            '对于代码折叠的情况,进行修正
            If DisplayLine.Real_IsBlockHeader And DisplayLine.Real_IsFolder And DisplayLine.Real_BlockLV = 1 Then
                orgCodeFold = Line.CodeFoldType.None
            End If
            Select Case orgCodeFold
                Case Line.CodeFoldType.Header
                    '只绘制上部的贯穿线
                    g.DrawLine(New Pen(ExForeColor), 57, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height, _
                                                     57, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height) / 2))
                Case Line.CodeFoldType.Footer
                    '只绘制下部的贯穿线
                    g.DrawLine(New Pen(ExForeColor), 57, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height) / 2) + 1, _
                                                     57, (DisplayLineNoForDraw - FirstVisiableLineNumber + 1) * ExFont.Height)
                Case Line.CodeFoldType.Whole
                    '绘制完整的贯穿线
                    g.DrawLine(New Pen(ExForeColor), 57, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height, _
                                                     57, (DisplayLineNoForDraw - FirstVisiableLineNumber + 1) * ExFont.Height)
            End Select
            '显示图标-代码折叠
            If DisplayLine.Real_IsBlockHeader Then
                '清除方框
                g.FillRectangle(New SolidBrush(ExBackColor), 52, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height - 10) / 2), 10, 10)
                '绘制方框
                g.DrawRectangle(New Pen(ExForeColor), 52, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height - 10) / 2), 10, 10)
                '绘制减号
                g.DrawLine(New Pen(ExForeColor), 54, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height) / 2), _
                           60, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height) / 2))
            End If
            If DisplayLine.Real_IsBlockHeader And DisplayLine.Real_IsFolder Then
                '绘制加号
                g.DrawLine(New Pen(ExForeColor), 57, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height - 10) / 2) + 2, _
                                                 57, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height - 10) / 2) + 8)
            End If
            '绘制展开时的块末
            If DisplayLine.Real_IsBlockFooter Then
                g.DrawLine(New Pen(ExForeColor), 57, (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height) / 2), 62, _
                           (DisplayLineNoForDraw - FirstVisiableLineNumber) * ExFont.Height + CInt((ExFont.Height) / 2))
            End If
        Next
        e.Graphics.DrawImage(bmp, 0, 0)
    End Sub
#End Region
#Region "事件"
    Dim SelectStartLine As Integer
    Dim selectEndLine As Integer
    Private Sub LineNumber_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        If e.Button = MouseButtons.Left And e.X < 50 Then
            Dim LineNumber As Integer
            '根据鼠标位置获得行号
            LineNumber = Math.Ceiling(e.Y / ExFont.Height) + FirstVisiableLineNumber - 1
            If LineNumber > ExDocument.MaxDisplayLineNumber Then Exit Sub
            SelectStartLine = ExDocument.GetMemoryLineByDisplayLineNumber(LineNumber).Dis_RealLineNumber
            selectEndLine = SelectStartLine
            RaiseEvent SelectTextByLineNumber(SelectStartLine, selectEndLine, FirstVisiableLineNumber)
        End If
    End Sub
    Private Sub LineNumber_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        If e.Button = MouseButtons.Left And e.X < 50 Then
            '鼠标左键处于被按下的状态
            Dim OrgFirstLine As Integer
            OrgFirstLine = FirstVisiableLineNumber
            If e.Y <= 0 Then
                '向上滚动文本
                If OrgFirstLine > 1 Then
                    selectEndLine = ExDocument.GetMemoryLineByDisplayLineNumber(OrgFirstLine - 1).Dis_RealLineNumber
                    OrgFirstLine -= 1
                Else
                    selectEndLine = 0
                End If
                RaiseEvent SelectTextByLineNumber(SelectStartLine, selectEndLine, OrgFirstLine)
                Exit Sub
            End If
            If e.Y > VisibleLines * ExFont.Height Then
                '向下滚动文本
                If FirstVisiableLineNumber + VisibleLines - 1 < ExDocument.MaxDisplayLineNumber Then
                    selectEndLine = ExDocument.GetMemoryLineByDisplayLineNumber(OrgFirstLine + VisibleLines).Dis_RealLineNumber
                    RaiseEvent SelectTextByLineNumber(SelectStartLine, selectEndLine, OrgFirstLine + 1)
                End If
                Exit Sub
            End If
            Dim DisplayNo As Integer = Math.Ceiling(e.Y / ExFont.Height) + FirstVisiableLineNumber - 1
            If DisplayNo > ExDocument.MaxDisplayLineNumber Then
                selectEndLine = ExDocument.MaxRealLineNumber
            Else
                selectEndLine = ExDocument.GetMemoryLineByDisplayLineNumber(DisplayNo).Dis_RealLineNumber
            End If
            RaiseEvent SelectTextByLineNumber(SelectStartLine, selectEndLine, OrgFirstLine)
        End If
    End Sub
    Private Sub LineNumber_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
        If e.X > 50 Then
            Dim LineNumber As Integer
            '根据鼠标位置获得行号
            LineNumber = Math.Ceiling(e.Y / ExFont.Height) + FirstVisiableLineNumber - 1
            If LineNumber > ExDocument.MaxDisplayLineNumber Then Exit Sub
            RaiseEvent LineClicked(LineNumber)
            Me.Refresh()
        End If
    End Sub
    ''' <summary>
    ''' 双击完成书签设置/撤销操作
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub LineNumber_MouseDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDoubleClick
        If e.X < 50 Then
            Dim LineNumber As Integer
            '根据鼠标位置获得行号
            LineNumber = Math.Ceiling(e.Y / ExFont.Height) + FirstVisiableLineNumber - 1
            If LineNumber > ExDocument.MaxDisplayLineNumber Then Exit Sub
            RaiseEvent LineDoubleClicked(LineNumber)
            Me.Refresh()
        End If
    End Sub
#End Region
#Region "列模式"
    Dim ColumnStartLine As Integer
    Dim ColumnEndLine As Integer
    Sub SetColumnModeStart(ByVal StartLine As Integer)
        ColumnStartLine = StartLine
        ColumnEndLine = StartLine
        Me.Refresh()
    End Sub
    Sub SetColumnModeEnd(ByVal EndLine As Integer)
        ColumnEndLine = EndLine
        Me.Refresh()
    End Sub
    Sub ClearColumnMode()
        ColumnStartLine = 0
        ColumnEndLine = 0
        Refresh()
    End Sub
#End Region
End Class
